package d6_thread_synchronized_lock;

import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//使用Lombok技术
@Data
//提供无参和有参
@NoArgsConstructor
//@AllArgsConstructor
public class Account {
    //卡号
    private String cardId;
    private int money;//余额
    //创建一个锁对象
    //利用final修饰保证-->无法对锁进行修改,要的就是锁唯一
    private final Lock lk = new ReentrantLock();//以及为它进行了复制所以不需要再写构造器,原本就应该这样.本来就要保证它的唯一
    //面向接口编程

    //不加final就要-->手写一个构造器就可以了
    public Account(String cardId, int money) {
        this.cardId = cardId;
        this.money = money;
    }

    //小明 小红拿同一个账户对象acc取钱
    //参数是要取款的前
    public void drawMoney(int money) {
        //获取当前线程的名字(知道谁来取)
        String name = Thread.currentThread().getName();
        //上锁
      //  lk.lock();-------->并非官方的做法
        //开始取钱
        //首先判断余额够不够
        try {
            lk.lock();
            if (this.money >= money) {

                //进行取钱
                System.out.println(name + "取钱成功, 吐出" + money);//这行
                //进行跟新余额//                                       ↓--------->这样子可能不会出现安全问题
                //                                                   ↓--------->这样子吐钱的时候,留足够了时间给,别的线程判断余额是否足够,更加容易出现线程安全的问题
                //                                                   ↓--------->这就是在模拟安全问题
                this.money -= money;//                              这行不要调过来
                //进行余额的输出
                System.out.println(name + "取钱成功后, 账户余额剩余:" + this.money);
            } else {
                //余额不足,不能完成取钱操作
                System.out.println(name + "来取钱, 当前账户余额不足,不能完成取钱操作");
            }
        } finally {
            lk.unlock();
        }
        //解锁
        //lk.unlock();->要确保一定要解锁-->使用

    }
}
